---
sidebar_position: 1
title: 认识loader
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

## 什么是loader

webpack是一个打包工具，它将根据项目内部的模块引用关系 做出分析并和处理， 最终输出外部客户端（如浏览器）能执行的代码，这就是`打包`。   
然而，webpack默认只能识别和处理js内容，对于其它众多的类型文件确无能为力（比如js中导入了一个txt文件，webpack就不知道如何处理txt，将会报错）。   
好在 webpack 开放了接口, 供三方开发出能解析非 js 的其它内容，这就是loader的由来。   
简言之 loader用于转换资源。  


> loader 用于对模块的源代码进行转换。loader 可以使你在 import 或 "load(加载)" 模块时预处理文件。因此，loader 类似于其他构建工具中“任务(task)”，并提供了处理前端构建步骤的得力方式。 ---[webpack官方介绍](https://www.webpackjs.com/concepts/loaders/)



## 如何使用
### 简单使用
比如 我js中导入了一个ts文件
<Tabs>
<TabItem value="index.js" label="index.js">

```js
const add = require("./add.js");

const res = add(1, 2);
console.log(res);
```

</TabItem>
<TabItem value="add.ts" label="add.ts">

```ts
module.exports = (x:number, y:number) => {
    return x + y;
};
```
</TabItem>
</Tabs>

默认webpack并不知道如何处理ts文件将会，此时交给它让它打包处理，将会报错：“入口文件代码存在报错，webpack不能解析处理出js之外的内容，您可能需要一个对应的loader”  
```shell
ERROR in ./src/add.ts 1:17
Module parse failed: Unexpected token (1:17)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> export default (x:number, y:number) => {
|     return x + y;
| };
 @ ./src/index.js 1:0-26 3:12-15
```

**🤔怎么办呢？**   

安装 `ts-loader`和`typescript`(ts-loader内部需要)，并在项目根目录创建一个空文件`tsconfig.json`（ts开发需要）
```
yarn add --dev typescript ts-loader
```
然后在webpack配置文件去配置此类型和loader对应处理关系rules
```js title="webpack.config.js"
module.exports = {
    // ...
    module:{
        rules:[
            // ...
            { test: /\.ts$/, use: 'ts-loader'}
        ]
    }
}
```


再次运行webpack进行编译打包，即可成功了。    
来我们看看打包后是如何处理ts代码的：打包后将ts代码中的类型删除了
```js
// ./src/add.ts
"./src/add.ts"(__unused_webpack_module, exports) {
    // ...
    exports["default"] = function (x, y) {
        return x + y;
    };
}
```
如此一来，经过webpack打包后的文件，就可以无障碍的运行在浏览器中了。       
有了（ts）loader的赋能,webpack便有能力处理.ts文件，也就是说loader增强webpack处理文件的能力。


### 链式调用
loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果（也就是应用过转换后的资源）传递给下一个 loader，依此类推。最后，链中的最后一个 loader，返回 webpack 所期望的 JavaScript。

链式调用这种设计有两个好处,一是保持单个 Loader 的单一职责,一定程度上降低代码的复杂度;

**🌰举个例子**   
比如我们引入css文件，
```js title="./src/index.js"
import style from "./style.css";

console.log(style);
```

要想被webpack合理的处理，首需要安装其loader `yarn add --dev css-loader`，然后配置rules
```js title="webpack.config.js"
{ test: /\.css$/, use: 'css-loader'}
```

最后我们打包，并执行打包后的代码，可以看到如此输出
![](https://alist.dingshaohua.com/d/ali/image-host/book-webpack/20240325121250.png?sign=FqYXJcbJX7rfoe4XHy2tflK5vqLZawe2R9NodFcvzrg=:0)



如果需要作用到页面上生效，我们还需要自己处理
```js title="./src/index.js"
import style from "./style.css";

// 在页面的head标签中插入一个link css的标签
const [[path, content]] = style;
const cssLink = document.createElement('link');
cssLink.rel = 'stylesheet';
cssLink.href = path;
document.head.appendChild(cssLink);
```
或者
```js title="./src/index.js"
import style from "./style.css";

// 在页面的head标签中插入一个style节点
const [[path, content]] = style;
const styleNode = document.createElement('style');
styleNode.innerText = content;
document.head.appendChild(styleNode);
```


这样太麻烦了，好在有三方loader帮我做了这件事情 `style-loader`
```js title="webpack.config.js"
module.exports = {
   // ...
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    // style-loader插入模式为styleTag（默认）的时候，
                    // 需要css-loader拿到具体的样式内容，所以需要先由css-loader处理下
                    'style-loader',  
                    'css-loader' 
                ],
            },
        ],
    },
};
```

### 内联使用
```js
import add from"ts-loader!./add.ts";

const res = add(1, 2);
console.log(res);
```

使用 ! 将资源中的 loader 分开
```js
import '!style-loader!css-loader?modules!./styles.css';
```
效果和在配置文件中使用一样，仅仅写法区别


## 传递参数
loader 可以通过 options 对象配置

还拿引入css为例子， 如果你想以link的方式插入外部文件，结合file-loader，配置style-loader的插件参数即可
```js title="webpack.config.js"
module.exports = {
   // ...
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    // style-loader插入模式为linkTag的时候，
                    // 需要file-loader拿到具体的样式文件的地址，所以需要先由file-loader处理下
                    {loader: "style-loader", options: { injectType: "linkTag" } },
                    { loader: "file-loader" },
                ],
            },
        ],
    },
};
```


## 解析 loader

loader 遵循标准 [模块解析](https://www.webpackjs.com/concepts/module-resolution/) 规则。 即绝/相对路径、node_modules中。
```js
{ loader: "css-loader" ,...},
{ loader: "./my-loaders/yml-loader" ,...},
```